home *** CD-ROM | disk | FTP | other *** search
- /*
-
- This is an example of am image compression codec that handles both
- compression and decompression of images as passed to it by the
- Image Compression manager. It is built as a Component Manager Component.
-
-
- The compression scheme here is 411 YUV. The image is stored as separate
- luminance and chrominance channels. For each 2x2 block of pixels in the
- source image we store 4 luminance (Y) components, 1 Y-Red component (U) and
- 1 Y-Blue (V) component. Each Y-component is stored as 6-bits, resulting in a
- savings of 2.4:1 over a 24-bit/pixel image (6*4 + 2*8)/4 = 10 bits/pixel.
-
- */
-
- #include <Memory.h>
- #include <Resources.h>
- #include <QuickDraw.h>
- #include <QDOffscreen.h>
- #include <OSUtils.h>
- #include <SysEqu.h>
- #include <Errors.h>
- #include <FixMath.h>
-
- #include "Image Codec.h"
-
-
- #define TYPE_NAME "\pExample" /* The name of this type of codec (not this instance) */
-
- #define EXAMPLE_CODEC_REV 1
- #define EXAMPLE_CODEC_VERSION 1
-
-
-
- /* some useful macros */
-
- #define R_W 0x4ccd
- #define G_W 0x970a
- #define B_W 0x1c29
- #define PIN(_n) ((_n) < 0 ? 0 : (_n) > 255 ? 255 : (_n))
-
-
-
-
- typedef struct { /* This is the structure we use to store our global data. */
- long *rwTable;
- long *gwTable;
- long *bwTable;
- char *giwTable;
- CodecInfo **info;
- } SharedGlobals;
-
- typedef struct { /* This is the structure we use to store our global data. */
- SharedGlobals *sharedGlob;
- } Globals;
-
-
- pascal ComponentResult
- OpenCodec(ComponentInstance self);
-
- pascal ComponentResult
- CloseCodec(Handle storage,ComponentInstance self);
-
- pascal ComponentResult
- CanDoSelector(short selector);
-
- pascal ComponentResult
- GetVersion();
-
- pascal void
- CompressStrip(char *data,char *baseAddr,short rowBytes,short w,SharedGlobals *sg);
-
- pascal void
- DecompressStrip(char *data,char *baseAddr,short rowBytes,short w,SharedGlobals *sg);
-
-
-
-
- /************************************************************************************
- * This is the main dispatcher for our codec. All calls from the codec manager
- * will come through here, with a unique selector and corresponding parameter block.
- *
- * This routine must be first in the code segment of the codec thing.
- */
-
- pascal long
- EXAMPLECODEC(ComponentParameters *thingo,char **storage)
- {
- /* If the selector is less than zero, it's a Component manager selector. */
-
- if ( thingo->what < 0 ) {
- switch ( thingo->what ) {
- case kComponentOpenSelect:
- return CallComponentFunction(thingo, (ComponentFunction) OpenCodec );
-
- case kComponentCloseSelect:
- return CallComponentFunctionWithStorage(storage,thingo, (ComponentFunction) CloseCodec );
-
- case kComponentCanDoSelect:
- return CallComponentFunction(thingo, (ComponentFunction) CanDoSelector);
-
- case kComponentVersionSelect :
- return CallComponentFunction(thingo, (ComponentFunction) GetVersion);
-
- default :
- return (paramErr);
- }
- }
-
- /*
- * Here we dispatch the rest of our calls. We use the magic thing manager routine which
- * calls our subroutines with the proper parameters. The prototypes are in Image Codec.h.
- */
-
- switch ( thingo->what ) {
- case codecPreCompress:
- return CallComponentFunctionWithStorage(storage,thingo,(ComponentFunction)CDPreCompress);
-
- case codecBandCompress:
- return CallComponentFunctionWithStorage(storage,thingo,(ComponentFunction)CDBandCompress);
-
- case codecPreDecompress:
- return CallComponentFunctionWithStorage(storage,thingo,(ComponentFunction)CDPreDecompress);
-
- case codecBandDecompress:
- return CallComponentFunctionWithStorage(storage,thingo,(ComponentFunction)CDBandDecompress);
-
- case codecCDSequenceBusy:
- return 0; /* our codec is never asynchronously busy */
-
- case codecGetCodecInfo:
- return CallComponentFunctionWithStorage(storage,thingo,(ComponentFunction)CDGetCodecInfo);
-
- case codecGetCompressedImageSize:
- return CallComponentFunctionWithStorage(storage,thingo,(ComponentFunction)CDGetCompressedImageSize);
-
- case codecGetMaxCompressionSize:
- return CallComponentFunctionWithStorage(storage,thingo,(ComponentFunction)CDGetMaxCompressionSize);
-
- case codecGetCompressionTime:
- return CallComponentFunctionWithStorage(storage,thingo,(ComponentFunction)CDGetCompressionTime);
-
- case codecGetSimilarity:
- return CallComponentFunctionWithStorage(storage,thingo,(ComponentFunction)CDGetSimilarity);
-
- case codecTrimImage:
- return CallComponentFunctionWithStorage(storage,thingo,(ComponentFunction)CDTrimImage);
-
- default:
- return(paramErr);
- }
- }
-
-
- /************************************************************************************
- * This gets called when the thing instance is opened. We allocate our storage at this
- * point. If we have shared globals, we check if they exist, and put a pointer to them
- * in our instance globals so that other calls can get to them.
- */
-
- pascal ComponentResult
- OpenCodec(ComponentInstance self)
- {
- SharedGlobals *sGlob;
- long i;
- Globals **glob;
- short resFile;
- THz saveZone;
- Handle h;
- Boolean inAppHeap;
- OSErr result = noErr;
-
- /*
- First we allocate storage. This should be a handle to any
- kind of data used by the thing instance.
-
- This is put in the system heap by default, or in the app
- heap if the codec is opened in the app heap.
-
- If you have data which can be shared among several instances (such
- as look-up tables ), then you should
- use the ComponentManager call "SetComponentRefCon" for this.
- */
-
- inAppHeap = ( GetComponentInstanceA5(self) != 0 );
- saveZone = GetZone();
- if ( !inAppHeap )
- SetZone(SystemZone());
-
- if ( (glob = (Globals **)NewHandleClear(sizeof(Globals))) == nil ) {
- result = MemError();
- goto obail;
- }
-
- SetComponentInstanceStorage(self,(Handle)glob);
-
- /*
- * Allocate and initialize tables. These sare shared across all instances
- * of this codecs, and are kept in the refcon.
- */
-
- if ( (sGlob=(SharedGlobals*)GetComponentRefcon((Component)self)) == nil ) {
- if ( (sGlob = (SharedGlobals*)NewPtrSys(sizeof(SharedGlobals))) != nil ) {
- if ((sGlob->rwTable = (long *)NewPtrSys(256*sizeof(long))) == nil ) {
- DisposPtr((Ptr)sGlob);
- result = MemError();
- goto obail;
- }
- if ((sGlob->gwTable = (long *)NewPtrSys(256*sizeof(long))) == nil ) {
- DisposPtr((Ptr)sGlob->rwTable);
- DisposPtr((Ptr)sGlob);
- result = MemError();
- goto obail;
- }
- if ( (sGlob->bwTable = (long *)NewPtrSys(256*sizeof(long))) == nil ) {
- DisposPtr((Ptr)sGlob->rwTable);
- DisposPtr((Ptr)sGlob->gwTable);
- DisposPtr((Ptr)sGlob);
- result = MemError();
- goto obail;
- }
- if ( (sGlob->giwTable = NewPtrSys(256)) == nil ) {
- DisposPtr((Ptr)sGlob->rwTable);
- DisposPtr((Ptr)sGlob->gwTable);
- DisposPtr((Ptr)sGlob->bwTable);
- DisposPtr((Ptr)sGlob);
- result = MemError();
- goto obail;
- }
- for ( i=0; i < 256; i++ )
- sGlob->rwTable[i] = i * R_W;
- for ( i=0; i < 256; i++ )
- sGlob->gwTable[i] = i * G_W;
- for ( i=0; i < 256; i++ )
- sGlob->bwTable[i] = i * B_W;
- for ( i=0; i < 256; i++ )
- sGlob->giwTable[i] = PIN((i<<16) / G_W);
- SetComponentRefcon((Component)self,(long)sGlob);
- resFile = OpenComponentResFile((Component)self);
- SetZone(SystemZone());
- h = Get1Resource(codecInfoResourceType,128);
- if ( h == nil ) {
- DisposHandle((Handle)glob);
- result = ResError();
- goto obail;
- }
- LoadResource(h);
- if ( ResError() ) {
- DisposHandle((Handle)glob);
- result = ResError();
- goto obail;
- }
- DetachResource(h);
- HNoPurge(h);
- CloseComponentResFile(resFile);
- SetZone(saveZone);
- if( h == 0 ) {
- result = MemError();
- goto obail;
- }
- sGlob->info = (CodecInfo **)h;
- }
- }
- (*glob)->sharedGlob = sGlob;
- obail:
- return(result);
- }
-
-
- /************************************************************************************
- * This gets called when the thing instance is closed. We need to get rid of any
- * instance storage here.
- */
-
- pascal ComponentResult
- CloseCodec(Handle storage,ComponentInstance self)
- {
- SharedGlobals *sGlob;
- long i;
- Globals **glob = (Globals **)storage;
-
- /* If we are closing our last instance, then we can chuck our shared globals. */
-
- if ( CountComponentInstances((Component)self) == 1) {
- if ( (sGlob=(SharedGlobals*)GetComponentRefcon((Component)self)) != nil ) {
- if ( sGlob->rwTable )
- DisposPtr((Ptr)sGlob->rwTable);
- if ( sGlob->gwTable )
- DisposPtr((Ptr)sGlob->gwTable);
- if ( sGlob->bwTable )
- DisposPtr((Ptr)sGlob->bwTable);
- if ( sGlob->giwTable )
- DisposPtr((Ptr)sGlob->giwTable);
- DisposPtr((Ptr)sGlob);
- SetComponentRefcon((Component)self,0);
- }
- }
-
- /* Dispose instance storage. */
-
- if ( glob )
- DisposHandle((Handle)storage);
- return(noErr);
- }
-
-
-
- /************************************************************************************
- * Return true if we can handle the selector, otherwise false.
- */
-
- pascal ComponentResult
- CanDoSelector(short selector)
- {
- switch(selector) {
- case codecPreCompress:
- case codecBandCompress:
- case codecPreDecompress:
- case codecBandDecompress:
- case codecCDSequenceBusy:
- case codecGetCodecInfo:
- case codecGetCompressedImageSize:
- case codecGetMaxCompressionSize:
- case codecGetCompressionTime:
- case codecGetSimilarity:
- case codecTrimImage:
- return(true);
- default:
- return (false);
- }
- }
-
-
- /************************************************************************************
- * Return the version of this component ( defines interface ) and revision level
- * of the code.
- */
-
- pascal ComponentResult
- GetVersion()
- {
- return ((EXAMPLE_CODEC_VERSION<<16) | EXAMPLE_CODEC_REV); /* interface version in hi word, code rev in lo word */
- }
-
-
- /************************************************************************************
- * CDPreCompress gets called before an image is compressed, or whenever the source pixmap
- * pixel size changes when compressing a sequence. We return information about
- * how we can compress the image to the codec manager, so that it can fit the source data
- * to our requirements. The ImageDescriptor is already filled in, so we can use it for
- * reference (or even add to it ). PixelSize is the pixel depth of the source pixmap, we
- * use this as a reference for deciding what we can do. The other parameters return information
- * to the CodecManager about what we can do. We can also do setup here if we want to.
- */
-
- pascal long
- CDPreCompress(Handle storage,register CodecCompressParams *p)
- {
- CodecCapabilities *capabilities = p->capabilities;
-
- /*
- * First we return which depth input pixels we can deal with - based on what the
- * app has available - we can only work with 32 bit input pixels.
- */
-
- switch ( (*p->imageDescription)->depth ) {
- case 16:
- capabilities->wantedPixelSize = 32;
- break;
- default:
- return(paramErr);
- break;
- }
-
- /* if the buffer is banded - return the smallest one we can deal with */
-
- capabilities->bandMin = 2;
-
- /* if the buffer is banded, return the increment it be should grown */
-
- capabilities->bandInc = 2;
-
-
- /*
- * If a codec needs the dimensions of the source pixmap to be of certain multiples
- * it can ask for the image to be extended out (via pixel replication) vertically
- * and/or horizontally.
- *
- * In our case, we're dealing with 2 by 2 blocks and therefore we want the image
- * height and width to both be multiples of 2. If either dimension is odd, we
- * ask it have it extended by one pixel.
- */
-
- capabilities->extendWidth = (*p->imageDescription)->width & 1;
- capabilities->extendHeight = (*p->imageDescription)->height & 1;
-
- return(noErr);
- }
-
-
- /************************************************************************************
- * CDBandCompress gets called when the codec manager wants us to compress an image, or a horizontal
- * band of an image. The pixel data at sBaseAddr is guaranteed to conform to the criteria we
- * demanded in BeginCompress.
- */
-
- pascal long
- CDBandCompress(Handle storage,register CodecCompressParams *p)
- {
- short width,height;
- Ptr cDataPtr,dataStart;
- long totalBytes = 0;
- short depth;
- Rect sRect;
- long offsetH,offsetV;
- Globals **glob = (Globals **)storage;
- register char *baseAddr;
- short numLines = p->stopLine - p->startLine;
- short rowBytes,stripBytes;
- char mmuMode = 1;
- register short y;
- ImageDescription **desc = p->imageDescription;
- OSErr result = noErr;
-
- /* If there is a progress proc, give it an open call at the start of this band. */
-
- if (p->progressProcRecord.progressProc)
- p->progressProcRecord.progressProc(codecProgressOpen,0,
- p->progressProcRecord.progressRefCon);
-
- width = (*desc)->width;
- height = (*desc)->height;
- depth = (*desc)->depth;
- dataStart = cDataPtr = StripAddress(p->data);
-
- /* figure out offset to first pixel in baseAddr from the pixelsize and bounds */
-
- rowBytes = p->srcPixMap.rowBytes & 0x3fff;
- sRect = p->srcPixMap.bounds;
- offsetH = sRect.left<<2;
- offsetV = sRect.top * rowBytes;
- baseAddr = p->srcPixMap.baseAddr += offsetH + offsetV;
- stripBytes = ((width+1)>>1) * 5;
-
- cDataPtr += (p->startLine>>1) * stripBytes;
- if ( p->flushProcRecord.flushProc ) {
- if ( p->bufferSize < stripBytes ) {
- result = codecSpoolErr;
- goto bail;
- }
- }
-
- for ( y=0; y < ((numLines+1)>>1); y++) {
- SwapMMUMode(&mmuMode);
- CompressStrip(cDataPtr,baseAddr,rowBytes,width,(*glob)->sharedGlob);
- SwapMMUMode(&mmuMode);
- cDataPtr += stripBytes;
- baseAddr += rowBytes<<1;
- if ( p->flushProcRecord.flushProc ) {
- if ( (result=p->flushProcRecord.flushProc(dataStart,stripBytes,
- p->flushProcRecord.flushRefCon)) != noErr) {
- goto bail;
- }
- cDataPtr = dataStart;
- }
- if (p->progressProcRecord.progressProc) {
- if ( (result=p->progressProcRecord.progressProc(codecProgressUpdatePercent,
- FixDiv(y,(numLines+1)>>1),p->progressProcRecord.progressRefCon)) != noErr )
- goto bail;
- }
- }
-
-
- if ( p->conditionFlags & codecConditionLastBand ) {
- (*p->imageDescription)->dataSize = ((width+1)>>1) * 5 * ((height+1)>>1); /* return the actual size of the compressed data */
- p->similarity = 0; /* we don't do frame differencing */
- }
-
- bail:
- /* If there is a progress proc, give it a close call at the end of this band. */
-
- if (p->progressProcRecord.progressProc)
- p->progressProcRecord.progressProc(codecProgressClose,0,
- p->progressProcRecord.progressRefCon);
-
- return(result);
- }
-
-
-
- /************************************************************************************
- * CDPreDecompress gets called before an image is decompressed. We return information about
- * how we can decompress the image to the codec manager, so that it can fit the destination data
- * to our requirements.
- */
-
- pascal long
- CDPreDecompress(Handle storage,register CodecDecompressParams *p)
- {
- register CodecCapabilities *capabilities = p->capabilities;
- Rect dRect = p->srcRect;
-
- /* Check if the matrix is okay for us. We don't do anything fancy. */
-
- if ( !TransformRect(p->matrix,&dRect,nil) )
- return(paramErr);
-
-
- /* Decide which depth compressed data we can deal with. */
-
- switch ( (*p->imageDescription)->depth ) {
- case 16:
- break;
- default:
- return(paramErr);
- break;
- }
-
- /* We can deal only 32 bit pixels. */
-
- capabilities->wantedPixelSize = 32;
-
- /* The smallest possible band we can do is 2 scan lines. */
-
- capabilities->bandMin = 2;
-
- /* We can deal with 2 scan line high bands. */
-
- capabilities->bandInc = 2;
-
- /* If we needed our pixels to be aligned on some integer multiple we would set these to
- * the number of pixels we need the dest extended by.
- */
-
- capabilities->extendWidth = p->srcRect.right & 1;
- capabilities->extendHeight = p->srcRect.bottom & 1;
-
- return(noErr);
- }
-
-
- /************************************************************************************
- * CDBandDecompress gets called when the codec manager wants us to decompress an image or a horizontal
- * band of an image. The pixel data at baseAddr is guaranteed to conform to the criteria we
- * demanded in BeginDecompress. If maskIn is true, then the mask data at mBaseAddr is valid, and
- * we need to clear bits in it that correspond to any pixels in the destination we do not want to
- * change. ( We always write all pixels, so we dont care. This mode is important only for those
- * codecs that have frame differencing and don't always write all the pixels. )
- */
-
- pascal long
- CDBandDecompress(Handle storage,register CodecDecompressParams *p)
- {
- Rect dRect;
- long offsetH,offsetV;
- Globals **glob = (Globals **)storage;
- short numLines = p->stopLine - p->startLine;
- short rowBytes,stripBytes;
- short width;
- register short y;
- register char *baseAddr;
- char *cDataPtr;
- char mmuMode = 1;
- OSErr result = noErr;
-
- /* Calculate the real base address based on the bounds rect. If its not
- a linear transformation, we dont do it. */
-
- dRect = p->srcRect;
- if ( !TransformRect(p->matrix,&dRect,nil) )
- return(paramErr);
-
- /* If there is a progress proc, give it an open call at the start of this band. */
-
- if (p->progressProcRecord.progressProc)
- p->progressProcRecord.progressProc(codecProgressOpen,0,
- p->progressProcRecord.progressRefCon);
-
- width = (*p->imageDescription)->width;
- rowBytes = p->dstPixMap.rowBytes;
- offsetH = (dRect.left - p->dstPixMap.bounds.left) * sizeof(long);
- offsetV = (dRect.top - p->dstPixMap.bounds.top) * rowBytes;
- baseAddr = p->dstPixMap.baseAddr + offsetH + offsetV;
-
- stripBytes = ((width+1)>>1) * 5;
-
- cDataPtr = StripAddress(p->data);
-
- /*
- * If we are skipping some data, we just skip it here. We can tell because
- * firstBandInFrame says this is the first band for a new frame, and
- * if startLine is not zero, then that many lines were clipped out.
- */
-
- if ( (p->conditionFlags & codecConditionFirstBand) && p->startLine != 0 ) {
- if ( p->dataProcRecord.dataProc ) {
- for ( y=0; y < p->startLine>>1; y++ ) {
- if ( (result=p->dataProcRecord.dataProc(&cDataPtr,stripBytes,
- p->dataProcRecord.dataRefCon)) != noErr ) {
- goto bail;
- }
- cDataPtr += stripBytes;
- }
- } else
- cDataPtr += (p->startLine>>1) * stripBytes;
- }
-
- /*
- * If theres a dataproc spooling the data to us, then we have to do the data
- * in whatever size chunks they want to give us.
- */
-
- for (y=0; y < (numLines+1)>>1; y++) {
- if (p->dataProcRecord.dataProc) {
- if ( (result=p->dataProcRecord.dataProc(&cDataPtr,stripBytes,
- p->dataProcRecord.dataRefCon)) != noErr ) {
- goto bail;
- }
- }
- SwapMMUMode(&mmuMode);
- DecompressStrip(cDataPtr,baseAddr,rowBytes,width,(*glob)->sharedGlob);
- SwapMMUMode(&mmuMode);
- baseAddr += rowBytes<<1;
- cDataPtr += stripBytes;
- if (p->progressProcRecord.progressProc) {
- if ( (result=p->progressProcRecord.progressProc(codecProgressUpdatePercent,
- FixDiv(y, (numLines+1)>>1),p->progressProcRecord.progressRefCon)) != noErr ) {
- goto bail;
- }
- }
- }
-
- p->data = cDataPtr;
-
- if ( p->conditionFlags & codecConditionLastBand ) {
- /* Tie up any loose ends on the last band of the frame. */
- }
-
- bail:
- /* If there is a progress proc, give it a close call at the end of this band. */
-
- if (p->progressProcRecord.progressProc)
- p->progressProcRecord.progressProc(codecProgressClose,0,
- p->progressProcRecord.progressRefCon);
-
-
- return(result);
- }
-
-
- /************************************************************************************
- * CDGetCodecInfo allows us to return information about ourselves to the codec manager.
- *
- * There will be a tool for determining appropriate values for the accuracy, speed
- * and level information. For now we estimate with scientific wild guessing.
- */
-
- pascal ComponentResult
- CDGetCodecInfo(Handle storage,CodecInfo *info)
- {
- Globals **glob = (Globals **)storage;
-
- if ( info == nil )
- return(paramErr);
- BlockMove((Ptr)*((*glob)->sharedGlob)->info,(Ptr)info,sizeof(CodecInfo));
- return(noErr);
- }
-
-
- /************************************************************************************
- * When CDGetSimilarity is called, we return the percent of the compressed image A that
- * is different from compressed image B. This can be used by applications that use sequence
- * dynamics as an indicator for editing image sequences.
- *
- * If the codec cannot do a direct similarity comparison, the ICM decompresses image A and
- * do a comparison with image B. This call is provided so that a codec can save the time
- * of the intermediate decompress if it can do the comparison directly.
- */
-
- pascal ComponentResult
- CDGetSimilarity(Handle storage,PixMap **src,Rect *srcRect,ImageDescriptionHandle desc,
- char *data,Fixed *dif)
- {
- #pragma unused(storage,src,srcRect,desc,data,dif,refcon)
-
- /* This call is not implemented yet. */
-
- return(codecUnimpErr);
- }
-
-
- /************************************************************************************
- * When CDGetCompressedImageSize is called, we return the size in bytes of the given compressed
- * data ( for one image frame).
- */
-
- pascal ComponentResult
- CDGetCompressedImageSize(Handle storage,ImageDescriptionHandle desc,Ptr data,long dataSize,
- DataProcRecordPtr dataProc,long *size)
- {
- #pragma unused(storage,data,dataSize,dataProc)
-
- short width =(*desc)->width;
- short height = (*desc)->height;
-
- if ( size == nil )
- return(paramErr);
-
- /*
- * Our data has a size which is deterministic based on the image size. If it were not we
- * could encode the size in the compressed data, or figure it out by walking the
- * compressed data.
- */
-
- *size = ((width+1)>>1) * 5 * ((height+1)>>1);
- return(noErr);
- }
-
-
- /************************************************************************************
- * When CDGetMaxCompressionSize is called, we return the maximum size the compressed data for
- * the given image would be in bytes.
- */
-
- pascal ComponentResult
- CDGetMaxCompressionSize(Handle storage,PixMap **src,Rect *srcRect,short depth,CodecQ quality,
- long *size)
- {
- #pragma unused(storage,src,depth,quality)
-
- short width = srcRect->right - srcRect->left;
- short height = srcRect->bottom - srcRect->top;
-
- /* we always end up with a fixed size. If we did not, we would return the worst case size */
-
- *size = ((width+1)>>1) * 5 * ((height+1)>>1);
-
- return(noErr);
- }
-
-
- /************************************************************************************
- * When CDGetCompressionTime is called, we return the approximate time for compressing
- * the given image would be in milliseconds. We also return the closest actual quality
- * we can handle for the requested value.
- */
-
- pascal ComponentResult
- CDGetCompressionTime(Handle storage,PixMap **src,Rect *srcRect,short depth,CodecQ *spatialQuality,
- CodecQ *temporalQuality,unsigned long *time)
- {
- #pragma unused(storage,src,srcRect,depth)
-
- if (time)
- *time = 0; /* we don't know how many */
-
- if (spatialQuality)
- *spatialQuality = codecNormalQuality; /* we have only one quality level for now */
-
- if (temporalQuality)
- *temporalQuality = 0; /* we cannot do temporal compression */
- return(noErr);
-
- }
-
-
- /************************************************************************************
- * When CDTrimImage is called, we take the given compressed data and return only the portion
- * which is represented by the trimRect. We can return a little more if we have too, but we
- * need only return enough so that the image in trimRect is properly displayed. We then
- * adjust the rectangle to corresond to the same rectangle in the new trimmed data.
- */
-
- pascal ComponentResult
- CDTrimImage(Handle storage,ImageDescriptionHandle desc,Ptr inData,long inDataSize,
- DataProcRecordPtr dataProc,Ptr outData,long outDataSize,FlushProcRecordPtr flushProc,
- Rect *trimRect,ProgressProcRecordPtr progressProc)
- {
- #pragma unused(storage)
-
- Rect rect = *trimRect;
- char *dataP,*odP,*startP;
- short trimOffTop;
- short trimOffBottom;
- short trimOffLeft;
- short trimOffRight;
- short bytesOffLeft;
- short newHeight,newWidth;
- long size;
- short stripBytes;
- short newStripBytes;
- short i,y;
- OSErr result = noErr;
-
-
-
- /* we dont handle spooling yet */
-
-
- if ( dataProc->dataProc == nil )
- dataProc = nil;
- if ( flushProc->flushProc == nil )
- flushProc = nil;
- if ( progressProc->progressProc == nil )
- progressProc = nil;
-
- if ( progressProc )
- progressProc->progressProc(codecProgressOpen,0,progressProc->progressRefCon);
- dataP = inData;
- newHeight = (*desc)->height;
- newWidth = (*desc)->width;
- stripBytes = ((newWidth+1)>>1) * 5; /* the number of bytes in a strip (2-scanlines/strip) */
-
- /* figure out how many 2x2 blocks we want to strip from each side of the image */
-
- trimOffTop = rect.top>>1;
- trimOffBottom = (newHeight - rect.bottom) >> 1;
- trimOffLeft = rect.left>>1;
- trimOffRight = (newWidth - rect.right) >> 1;
-
- /* point to the start of the first strip we are using */
-
- startP = dataP + stripBytes * trimOffTop;
-
-
- /* make the trim values pixel based */
-
- trimOffLeft <<= 1;
- trimOffTop <<= 1;
- trimOffBottom <<= 1;
- trimOffRight <<= 1;
-
- /* calculate new height and width */
-
- newHeight -= trimOffTop + trimOffBottom;
- newWidth -= trimOffLeft + trimOffRight;
-
- /* calc size in bytes of strips of the new width */
-
- newStripBytes = ((newWidth+1)>>1) * 5;
-
- /* figure number of bytes to toss at the beginning of each strip */
-
- bytesOffLeft = (trimOffLeft>>1) * 5;
-
- /* figure size of new trimmed image */
-
- size = newStripBytes * (newHeight>>1);
-
- /* make sure it's gonna fit */
-
- if ( size > outDataSize ) {
- result = codecErr;
- goto bail;
- }
-
- /* now go through the strips and copy the needed portion of each to the new data */
-
- if ( dataProc ) {
- short rightBytes = stripBytes - newStripBytes - bytesOffLeft;
- for ( y=0; y < trimOffTop; y++ ) {
- if ( (result=dataProc->dataProc(&inData,stripBytes,dataProc->dataRefCon)) != noErr )
- goto bail;
- inData += stripBytes;
- if (progressProc ) {
- if ( (result=progressProc->progressProc(codecProgressUpdatePercent,
- FixDiv(y, (*desc)->height),progressProc->progressRefCon)) != noErr)
- goto bail;
- }
- }
- for ( y=0; y < newHeight; y+= 2) {
- if ( bytesOffLeft ) {
- if ( (result=dataProc->dataProc(&inData,bytesOffLeft,dataProc->dataRefCon)) != noErr )
- goto bail;
- inData += bytesOffLeft;
- }
- if ( (result=dataProc->dataProc(&inData,newStripBytes,dataProc->dataRefCon)) != noErr )
- goto bail;
- if ( flushProc ) {
- if ( (result=flushProc->flushProc(inData,newStripBytes,flushProc->flushRefCon)) != noErr )
- goto bail;
- }
- else {
- BlockMove(inData,outData,newStripBytes);
- outData += newStripBytes;
- }
- inData += newStripBytes;
- if ( rightBytes ) {
- if ( (result=dataProc->dataProc(&inData,rightBytes,dataProc->dataRefCon)) != noErr )
- goto bail;
- inData += rightBytes;
- }
- if (progressProc) {
- if ( (result=progressProc->progressProc(codecProgressUpdatePercent,
- FixDiv((trimOffTop + y),(*desc)->height),progressProc->progressRefCon)) != noErr )
- goto bail;
- }
- }
- }
- else {
- inData += stripBytes * trimOffTop;
- for ( y=0; y < newHeight; y += 2, inData += stripBytes) {
- if ( flushProc ) {
- if ( (result=flushProc->flushProc(inData + bytesOffLeft,newStripBytes,flushProc->flushRefCon)) != noErr )
- goto bail;
- }
- else {
- BlockMove(inData + bytesOffLeft,outData,newStripBytes);
- outData += newStripBytes;
- }
- if (progressProc ) {
- if ( (result=progressProc->progressProc(codecProgressUpdatePercent,
- FixDiv((trimOffTop + y),(*desc)->height),progressProc->progressRefCon)) != noErr )
- goto bail;
- }
- }
- }
-
- /* adjust the rectangle to reflect our changes */
-
- trimRect->top -= trimOffTop;
- trimRect->bottom -= trimOffTop;
- trimRect->left -= trimOffLeft;
- trimRect->right -= trimOffLeft;
-
- /* return the new width and height in the image description and the size */
-
- (*desc)->height = newHeight;
- (*desc)->width = newWidth;
- (*desc)->dataSize = size;
- bail:
- if ( progressProc )
- progressProc->progressProc(codecProgressClose,0,progressProc->progressRefCon);
-
- return(result);
-
-
- }
-
-
- #ifndef HAS_ASM /* we could do this part in assembly for speed if we desired */
-
-
- #define READPIXEL(n) \
- l = *lp++; \
- r = (l>>16); \
- g = (l>>8); \
- b = l; \
- yt = (R_W*r + G_W*g + B_W*b); \
- if ( yt > ((256L<<16)-1) ) yt = ((256L<<16)-1); \
- ys[n] = yt>>16; \
- y += yt; \
- u += r; \
- v += b;
-
- #define READPIXEL_T(n) \
- l = *lp++; \
- r = (l>>16); \
- g = (l>>8); \
- b = l; \
- yt = (sg->rwTable[r] + sg->gwTable[g] + sg->bwTable[b]); \
- if ( yt > ((256L<<16)-1) ) yt = ((256L<<16)-1); \
- ys[n] = yt>>16; \
- y += yt; \
- u += r; \
- v += b;
-
-
- pascal void
- CompressStrip(char *data,char *baseAddr,short rowBytes,short len,SharedGlobals *sg)
- {
-
- register long l,*lp = (long *)baseAddr;
- register unsigned char r,g,b;
- unsigned char ys[4];
- register long y,yt;
- short u,v;
- short rowLongs = (rowBytes>>2);
-
-
- len++;
- len>>=1;
- if ( sg ) {
- while ( len-- > 0) {
- y = u = v = 0;
- READPIXEL_T(0);
- READPIXEL_T(1);
- lp += rowLongs-2;
- READPIXEL_T(2);
- READPIXEL_T(3);
- lp -= rowLongs;
-
- y >>= 16;
- u = (u - y)>>4;
- v = (v - y)>>4;
-
- l = (long)(0xfc & (ys[0])) << 24;
- l |= (long)(0xfc & (ys[1])) << 18;
- l |= (long)(0xfc & (ys[2])) << 12;
- l |= (long)(0xfc & (ys[3])) << 6;
- l |= u & 0xff;
- *(long *)data = l;
- data += sizeof(long);
- *data++ = v;
- }
- } else {
- while ( len-- > 0) {
- y = u = v = 0;
- READPIXEL(0);
- READPIXEL(1);
- lp += rowLongs-2;
- READPIXEL(2);
- READPIXEL(3);
- lp -= rowLongs;
-
- y >>= 16;
- u = (u - y)>>4;
- v = (v - y)>>4;
-
- l = (long)(0xfc & (ys[0])) << 24;
- l |= (long)(0xfc & (ys[1])) << 18;
- l |= (long)(0xfc & (ys[2])) << 12;
- l |= (long)(0xfc & (ys[3])) << 6;
- l |= u & 0xff;
- *(long *)data = l;
- data += sizeof(long);
- *data++ = v;
- }
- }
- }
-
-
-
-
- #define WRITEPIXEL \
- r = PIN(u+y); \
- b = PIN(v+y); \
- y <<= 16; \
- y -= r * R_W; \
- y -= b * B_W; \
- g = PIN(y / G_W); \
- *lp++ = (long) ( (long) r <<16) | ( (long) g <<8) | b;
-
- #define WRITEPIXEL_T \
- r = PIN(u+y); \
- b = PIN(v+y); \
- y <<= 16; \
- y -= sg->rwTable[r]; \
- y -= sg->bwTable[b]; \
- g = sg->giwTable[PIN(y>>16)]; \
- *lp++ = (long) ( (long) r <<16) | ( (long) g <<8) | b;
-
- pascal void
- DecompressStrip(char *data,char *baseAddr,short rowBytes,short len,SharedGlobals *sg)
- {
- register long y;
- register unsigned char r,g,b;
- register long l,*lp;
- long u,v;
- unsigned char ys[4];
- short rowLongs = (rowBytes>>2);
- short blen = len;
-
- lp = (long *)baseAddr;
- blen++;
- blen >>= 1;
- if ( sg ) {
- while ( blen-- > 0 ) {
- l = *(long *)data;
- data += sizeof(long);
- ys[0] = (0xfc & (l>>24));
- ys[1] = (0xfc & (l>>18));
- ys[2] = (0xfc & (l>>12));
- ys[3] = (0xfc & (l>>6));
- u = (char)l;
- v = *data++;
- u<<=2;
- v<<=2;
- y = ys[0];
- WRITEPIXEL_T;
- y = ys[1];
- WRITEPIXEL_T;
- lp += rowLongs - 2;
- y = ys[2];
- WRITEPIXEL_T;
- y = ys[3];
- WRITEPIXEL_T;
- lp -= rowLongs;
- }
- } else {
- while ( blen-- > 0 ) {
- l = *(long *)data;
- data += sizeof(long);
- ys[0] = (0xfc & (l>>24));
- ys[1] = (0xfc & (l>>18));
- ys[2] = (0xfc & (l>>12));
- ys[3] = (0xfc & (l>>6));
- u = (char)l;
- v = *data++;
- u<<=2;
- v<<=2;
- y = ys[0];
- WRITEPIXEL;
- y = ys[1];
- WRITEPIXEL;
- lp += rowLongs - 2;
- y = ys[2];
- WRITEPIXEL;
- y = ys[3];
- WRITEPIXEL;
- lp -= rowLongs;
- }
- }
- }
-
-
- #endif
-
-
-